package cn.holy.app.xcddt.repository

import androidx.lifecycle.LiveData

import cn.holy.app.xcddt.app.App
import cn.holy.app.xcddt.database.dao.RecordDao
import cn.holy.app.xcddt.database.dao.RecordGroupDao
import cn.holy.app.xcddt.domain.RecordBean
import cn.holy.app.xcddt.domain.RecordCheckBean
import cn.holy.app.xcddt.domain.RecordGroup
import cn.holy.app.xcddt.domain.net.ApiResponse
import cn.holy.app.xcddt.net.ApiClient
import cn.holy.app.xcddt.net.callback.LoadingCallback
import cn.holy.app.xcddt.net.callback.ProgressCallback
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken

import okhttp3.MediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody
import rx.Observable
import rx.Observer
import rx.Subscriber
import rx.android.schedulers.AndroidSchedulers
import rx.functions.Func1
import rx.schedulers.Schedulers
import top.zibin.luban.Luban
import java.io.File
import java.util.*
import javax.inject.Inject


/**
 * Created by 69568 on 2018/2/24.
 */

class RecordRepository @Inject
constructor(private val recordDao: RecordDao, private val recordGroupDao: RecordGroupDao) {

    val localRecords: LiveData<List<RecordBean>>?
        get() = App.userInfo?.id?.let { id ->
            return@let recordDao.queryAll(id)
        }

    fun uploadLocalRecords(records: ArrayList<RecordBean>, callback: ProgressCallback) {

        loopUpload(records, callback)
    }

    fun countLocalRecord(record_num: Int): Long? {
        App.userInfo?.let {
            return recordDao.countByRecordNumber(record_num, it.id)
        }
        return 0
    }


    fun netGroup(callback: LoadingCallback<Int>) {
        ApiClient.webService.recordNum().subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object : Subscriber<ApiResponse<Int>>() {
                    override fun onNext(t: ApiResponse<Int>) {
                        if (t.code == 200) {
                            callback.onSuccess(t.data!!)
                        }
                    }

                    override fun onCompleted() {
                        callback.onCompleted()
                    }

                    override fun onError(e: Throwable) {
                        callback.onError(e.localizedMessage)
                    }

                    override fun onStart() {
                        super.onStart()
                        callback.onStart()
                    }

                })
    }

    fun loadArchivesByGroup(page: Int, callback: LoadingCallback<ArrayList<RecordGroup>>) {
        ApiClient.webService.archivesByGroup(page).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object : Subscriber<ApiResponse<ArrayList<RecordGroup>>>() {
                    override fun onNext(t: ApiResponse<ArrayList<RecordGroup>>) {
                        if (t.code == 200) {
                            callback.onSuccess(t.data!!)
                        } else {
                            callback.onError(t.msg!!)
                        }
                    }

                    override fun onStart() {
                        super.onStart()
                        callback.onStart()
                    }

                    override fun onError(e: Throwable?) {
                        e?.let {
                            callback.onError(e.localizedMessage)
                        }

                    }

                    override fun onCompleted() {
                        callback.onCompleted()
                    }


                })
    }

    fun loadArcives(page: Int, status: Int, callback: LoadingCallback<List<RecordBean>>) {


        ApiClient.webService.archives(page, status).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object : Subscriber<ApiResponse<ArrayList<RecordBean>>>() {
                    override fun onStart() {
                        super.onStart()
                        callback.onStart()
                    }

                    override fun onError(e: Throwable?) {
                        callback.onError(e!!.localizedMessage)
                    }

                    override fun onCompleted() {
                        callback.onCompleted()
                    }

                    override fun onNext(result: ApiResponse<ArrayList<RecordBean>>) {
                        if (result.code == 200) {
                            callback.onSuccess(result.data!!)
                        } else {
                            callback.onError(result.msg!!)
                        }
                    }

                })
    }


    fun saveRecordUserNames(users: ArrayList<String>) {
        val gson = Gson()
        val json = gson.toJson(users)
        App.sharedPreferences.edit().putString("record_username", json).apply()

    }

    fun loadRecordUserNames(): ArrayList<String> {
        val gson = Gson()
        val record_username = App.sharedPreferences.getString("record_username", "[]")
        val arrayList = gson.fromJson<ArrayList<String>>(record_username, object : TypeToken<ArrayList<String>>() {}.type)
        return arrayList
    }

    fun uploadCheck(photos: ArrayList<String>, record_no: String, callback: LoadingCallback<RecordCheckBean>) {
        val builder = MultipartBody.Builder().setType(MultipartBody.FORM)
        photos.forEach({ path ->
            val file = File(path)
            builder.addFormDataPart("photos[]", file.name, RequestBody.create(MediaType.parse("images/*"), file))
        })

        builder.addFormDataPart("record_no", record_no)
        ApiClient.webService.uploadCheck(builder.build()).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object : Subscriber<ApiResponse<RecordCheckBean>>() {

                    override fun onCompleted() {
                        callback.onCompleted()
                    }

                    override fun onError(e: Throwable?) {
                        e?.let {
                            callback.onError(e.localizedMessage)
                        }
                    }

                    override fun onNext(result: ApiResponse<RecordCheckBean>) {
                        if (result.code == 200) {
                            callback.onSuccess(result.data!!)
                        } else {
                            callback.onError(result.msg!!)
                        }
                    }
                })
    }


    private fun loopUpload(records: ArrayList<RecordBean>, callback: ProgressCallback) {
        callback.onStart()
        var uploadCount = 0
        var uploadItem: RecordBean? = null
        records.forEach { item ->
            if (item.upload == 1) {
                uploadCount++
                callback.onProgress(records.size, uploadCount)
            } else {
                uploadItem = item
            }

        }

        if (records.size > uploadCount) {

            val recordBean = uploadItem!!
            Observable.just(recordBean).observeOn(Schedulers.io())
                    .flatMap(Func1<RecordBean, Observable<ApiResponse<String>>> {
                        val builder = MultipartBody.Builder().setType(MultipartBody.FORM)
                        if (recordBean.video != null) {
                            val video_path = recordBean.video
                            val file = File(video_path)
                            builder.addFormDataPart("video", file.name, RequestBody.create(MediaType.parse("video/*"), file))
                            val video_thumb_file = Luban.with(App.inst).load(recordBean.videoThumb)
                                    .get().first()
                            builder.addFormDataPart("video_thumb", video_thumb_file.name, RequestBody.create(MediaType.parse("image/*"), video_thumb_file))
                        }
                        if (recordBean.audio != null) {
                            val file = File(recordBean.audio)
                            builder.addFormDataPart("audio", file.name, RequestBody.create(MediaType.parse("audio/*"), file))
                        }
                        if (recordBean.photos != null && recordBean.photos!!.isNotEmpty()) {

                            val files = Luban.with(App.inst).load(recordBean.photos)
                                    .get()
                            files.forEach({ file ->
                                builder.addFormDataPart("photos[]", file.name, RequestBody.create(MediaType.parse("images/*"), file))
                            })
                        }
                        if (recordBean.address != null) {
                            builder.addFormDataPart("address", recordBean.address!!)
                        }
//            if (recordBean.record_no != null) {
//                        builder.addFormDataPart("record_no", recordBean.record_no)
                        builder.addFormDataPart("message", recordBean.message!!)
                        builder.addFormDataPart("record_username", recordBean.record_username!!)
                        builder.addFormDataPart("record_people", recordBean.record_people!!)
                        builder.addFormDataPart("record_num", recordBean.record_num.toString())
                        builder.addFormDataPart("latitude", recordBean.latitude.toString())
                        builder.addFormDataPart("longitude", recordBean.longitude.toString())
                        builder.addFormDataPart("record_date", (recordBean.record_date.time / 1000).toString())
                        return@Func1 ApiClient.webService.upload(builder.build())
                    })
                    .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                    .subscribe( {
                        result->
                        if (result.code == 200) {
                            recordBean.upload = 1
                            recordDao.update(recordBean)
                            loopUpload(records, callback)
                        } else {
                            callback.onError(result.msg!!)
                        }
                    },{
                        e->
                        callback.onError(e.localizedMessage)
                    },{

                    })
//            }
//            ApiClient.webService.upload(builder.build()).subscribeOn(Schedulers.io())
//                    .observeOn(AndroidSchedulers.mainThread())
//                    .subscribe(object : Subscriber<ApiResponse<String>>() {
//                        override fun onCompleted() {
//                            callback.onCompleted()
//                        }
//
//                        override fun onError(e: Throwable?) {
//
//                            callback.onError(e!!.localizedMessage)
//                        }
//
//                        override fun onNext(result: ApiResponse<String>) {
//                            if (result.code == 200) {
//                                recordBean.upload = 1
//                                recordDao.update(recordBean)
//                                loopUpload(records, callback)
//                            } else {
//                                callback.onError(result.msg!!)
//                            }
//                        }
//                    })
        } else {
            callback.onSuccess()
        }


    }

    fun loadRecords(record_num: Int): LiveData<MutableList<RecordBean>>? {
//        if (App.userInfo?.let {  })
        App.userInfo?.let {
            return recordDao.queryByRecordNumber(record_num, it.id)
        }

        return null
    }

    fun loadRecord(id: Int): LiveData<RecordBean>? {
        return recordDao.queryById(id)
    }

    val lastRecordGroup: RecordGroup?
        get() = App.userInfo?.id?.let { id ->
            return@let recordGroupDao.lastGroup(id)
        }

    val recordRecordGroup: LiveData<List<RecordGroup>>?
        get() = App.userInfo?.id?.let { id ->
            return@let recordGroupDao.queryAll(id)
        }

    fun saveRecord(recordBean: RecordBean) {
        recordDao.save(recordBean)
    }

    fun removeRecords(recordBeans: ArrayList<RecordBean>) {
        var deletes = ArrayList<Int>()
        recordBeans.forEach { it -> deletes.add(it.id) }
        recordDao.deleteRecords(deletes)
    }

    fun countGroup(): Int {
        App.userInfo?.id?.let { id ->
            return recordGroupDao.countGroups(id)
        }
        return 0

    }

    fun loadGroup(record_num: Int): RecordGroup? {
        return recordGroupDao.loadGroup(record_num)
    }

    fun saveRecordGroup(recordGroup: RecordGroup) {
        recordGroupDao.save(recordGroup)
    }

    interface LoopExecutor {
        fun exec()
    }
}
